home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIAppleTalk.cp < prev    next >
Text File  |  1995-11-05  |  21KB  |  1,062 lines

  1. /*********************************************************************
  2. Project    :    GUSI                    -    Grand Unified Socket Interface
  3. File        :    GUSIAppleTalk.cp    -    Appletalk Sockets
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIAppletalk.cp,v $
  8. Revision 1.4  1994/12/30  19:37:23  neeri
  9. Wake up process on completion to improve performance.
  10.  
  11. Revision 1.3  1994/08/10  00:31:28  neeri
  12. Sanitized for universal headers.
  13.  
  14. Revision 1.2  1994/05/01  23:29:28  neeri
  15. Enable recvfrom with non-NULL from address.
  16.  
  17. Revision 1.1  1994/02/25  02:28:11  neeri
  18. Initial revision
  19.  
  20. Revision 0.18  1993/12/30  00:00:00  neeri
  21. Fiddle with select()
  22.  
  23. Revision 0.17  1993/11/17  00:00:00  neeri
  24. Delay opening AppleTalk services
  25.  
  26. Revision 0.16  1993/09/01  00:00:00  neeri
  27. Throw out nonbreaking spaces
  28.  
  29. Revision 0.15  1993/02/07  00:00:00  neeri
  30. New configuration technique
  31.  
  32. Revision 0.14  1993/01/17  00:00:00  neeri
  33. Handle user interrupts more carefully.
  34.  
  35. Revision 0.13  1992/12/07  00:00:00  neeri
  36. Use flags
  37.  
  38. Revision 0.12  1992/10/05  00:00:00  neeri
  39. I was a teenage NBP werewolf
  40.  
  41. Revision 0.11  1992/09/13  00:00:00  neeri
  42. Always complete write
  43.  
  44. Revision 0.10  1992/09/07  00:00:00  neeri
  45. Implement ioctl()
  46.  
  47. Revision 0.9  1992/08/10  00:00:00  neeri
  48. Improve select()
  49.  
  50. Revision 0.8  1992/07/28  00:00:00  neeri
  51. Separate creating symaddrs from registering them
  52.  
  53. Revision 0.7  1992/07/26  00:00:00  neeri
  54. Error in using memccpy()
  55.  
  56. Revision 0.6  1992/07/21  00:00:00  neeri
  57. Support symbolic addresses
  58.  
  59. Revision 0.5  1992/07/13  00:00:00  neeri
  60. Make AppleTalkSockets available to other socket classes.
  61.  
  62. Revision 0.4  1992/05/18  00:00:00  neeri
  63. Out of band data
  64.  
  65. Revision 0.3  1992/05/18  00:00:00  neeri
  66. Basic functions work
  67.  
  68. Revision 0.2  1992/05/12  00:00:00  neeri
  69. NBP stuff
  70.  
  71. Revision 0.1  1992/05/10  00:00:00  neeri
  72. ADSPStreams
  73.  
  74. *********************************************************************/
  75.  
  76. #include "GUSI_P.h"
  77.  
  78. #include <Errors.h>
  79. #include <ADSP.h>
  80. #include <Devices.h>
  81. #include <GestaltEqu.h>
  82. #include <PLStringFuncs.h>
  83. #include <LowMem.h>
  84.  
  85. #include <Strings.h>
  86.  
  87. #include <sys/types.h>
  88.  
  89. class AtlkSymAddr;
  90.  
  91. class AppleTalkSocketDomain : public SocketDomain {
  92.     short                        dspRefNum;
  93.     
  94.     void                        DoMPPOpen();
  95. public:
  96.     AppleTalkSocketDomain();
  97.     
  98.     AddrBlock                node;
  99.     
  100.                 short            GetDSP();        
  101.                 Boolean        Validate();
  102.     virtual    Socket *     socket(int type, short protocol);
  103.     virtual int choose(
  104.                         int         type, 
  105.                         char *     prompt, 
  106.                         void *     constraint,        
  107.                         int         flags,
  108.                          void *     name, 
  109.                         int *     namelen);
  110. };
  111.  
  112. class AppleTalkSocket : public Socket    {        // That's what this file's all about
  113.     friend class AppleTalkSocketDomain;
  114. protected:
  115.     Boolean            nonblocking;
  116.     Boolean            ownSocket;
  117.     Boolean            readShutDown;
  118.     Boolean            writeShutDown;
  119.     u_char            socket;
  120.     AddrBlock        peer;
  121.     AtlkSymAddr *    symaddr;
  122.  
  123.                     AppleTalkSocket(u_char sock = 0);
  124.  
  125.     virtual         ~AppleTalkSocket();
  126.  
  127. #if !GENERATINGCFM
  128.     friend pascal void ADSPCompletion68K();
  129.     Ptr            processA5;    /* Our A5 world */
  130. #endif    
  131. public:
  132.     virtual int    bind(void * name, int namelen);
  133.     virtual int getsockname(void * name, int * namelen);
  134.     virtual int getpeername(void *name, int *namelen);
  135.     virtual int    fcntl(unsigned int cmd, int arg);
  136.     virtual int    ioctl(unsigned int request, void *argp);
  137.     void            Ready();
  138. };
  139.  
  140. struct ADSPSockBuffers {
  141.     enum {qSize    =    4150};
  142.  
  143.     u_char    attnBuf[attnBufSize];
  144.     u_char    sendBuf[qSize];
  145.     u_char    recvBuf[qSize];
  146. };
  147.  
  148. typedef ADSPSockBuffers * ADSPBufPtr;
  149.  
  150. class ADSPSocket;
  151.  
  152. #if PRAGMA_ALIGN_SUPPORTED
  153. #pragma options align=mac68k
  154. #endif
  155. struct AnnotatedADSPParamBlock : public DSPParamBlock {
  156.     AnnotatedADSPParamBlock(ADSPSocket * owner) : sock(owner) { };
  157.     
  158.     ADSPSocket *    sock;
  159. };
  160. #if PRAGMA_ALIGN_SUPPORTED
  161. #pragma options align=reset
  162. #endif
  163.  
  164. class ADSPSocket : public AppleTalkSocket {
  165.     friend class AppleTalkSocketDomain;
  166.  
  167.                     ADSPSocket(u_char sock = 0);
  168.  
  169.     TRCCB    *        ccb;
  170.     DSPPBPtr        pb;
  171.     ADSPBufPtr    bufs;
  172.  
  173.     int            Init();
  174.     void            UnInit(Boolean abort);
  175.     Boolean        Waiting();
  176.     Boolean        Up();
  177. public:
  178.     virtual int listen(int qlen);
  179.     virtual int connect(void * address, int addrlen);
  180.     virtual Socket * accept(void * address, int * addrlen);
  181.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  182.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  183.     virtual int shutdown(int how);
  184.     virtual int    ioctl(unsigned int request, void *argp);
  185.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  186.  
  187.     virtual         ~ADSPSocket();
  188. };
  189.  
  190. class AtlkSymAddr {
  191.     NamesTableEntry * nte;
  192.     Boolean    legit;
  193. public:
  194.     AtlkSymAddr(const EntityName & name);
  195.  
  196.     ~AtlkSymAddr();
  197.  
  198.     void Register(u_char socket);
  199. };
  200.  
  201. int AtlkLookup(const EntityName & name, AddrBlock * addr);
  202.  
  203. AppleTalkSocketDomain    AppleTalkSockets;
  204. const AddrBlock            NoFilter    =    {0, 0, 0};
  205.  
  206. /************************ AppleTalkSocket members ************************/
  207.  
  208. AppleTalkSocket::AppleTalkSocket(u_char sock)
  209. {
  210.     socket            =    sock;
  211.     ownSocket        =    !sock;
  212.     nonblocking        =    false;
  213.     readShutDown    =    false;
  214.     writeShutDown    =    false;
  215.     symaddr            =    nil;
  216.     peer                =    NoFilter;
  217.  
  218. #if !GENERATINGCFM
  219.     processA5        = LMGetCurrentA5();
  220. #endif    
  221. }
  222.  
  223.  
  224. inline void AppleTalkSocket::Ready() 
  225. {
  226.     AppleTalkSockets.Ready();
  227. }
  228.  
  229. AppleTalkSocket::~AppleTalkSocket()
  230. {
  231.     if (socket && ownSocket)    {
  232.         MPPParamBlock    mpp;
  233.  
  234.         mpp.DDP.socket    =    socket;
  235.  
  236.         PCloseSkt(&mpp, false);
  237.     }
  238.  
  239.     if (symaddr)
  240.         delete symaddr;
  241. }
  242.  
  243. int AppleTalkSocket::fcntl(unsigned int cmd, int arg)
  244. {
  245.     switch (cmd)    {
  246.     case F_GETFL:
  247.         if (nonblocking)
  248.             return FNDELAY;
  249.         else
  250.             return 0;
  251.     case F_SETFL:
  252.         if (arg & FNDELAY)
  253.             nonblocking = true;
  254.         else
  255.             nonblocking = false;
  256.  
  257.         return 0;
  258.     default:
  259.         return GUSI_error(EOPNOTSUPP);
  260.     }
  261. }
  262.  
  263. int AppleTalkSocket::ioctl(unsigned int request, void *argp)
  264. {
  265.     switch (request)    {
  266.     case FIONBIO:
  267.         nonblocking    =    (Boolean) *(long *) argp;
  268.  
  269.         return 0;
  270.     default:
  271.         return GUSI_error(EOPNOTSUPP);
  272.     }
  273. }
  274.  
  275. int AppleTalkSocket::bind(void *sa_name, int)
  276. {
  277.  
  278.     switch (*(short *) sa_name)    {
  279.     case AF_APPLETALK:
  280.         {
  281.             struct sockaddr_atlk *    addr = (struct sockaddr_atlk *) sa_name;
  282.  
  283.             if (socket || !addr->addr.aSocket)
  284.                 return GUSI_error(EINVAL);
  285.  
  286.             socket        =    addr->addr.aSocket;
  287.             ownSocket    =    false;
  288.         }
  289.         break;
  290.     case ATALK_SYMADDR:
  291.         {
  292.             struct sockaddr_atlk_sym *    addr = (struct sockaddr_atlk_sym *) sa_name;
  293.  
  294.             symaddr        =    new AtlkSymAddr(addr->name);
  295.  
  296.             if (errno)    {
  297.                 delete symaddr;
  298.                 symaddr = nil;
  299.  
  300.                 return -1;
  301.             }
  302.         }
  303.         break;
  304.     default:
  305.         return GUSI_error(EAFNOSUPPORT);
  306.     }
  307.  
  308.     return 0;
  309. }
  310.  
  311. int AppleTalkSocket::getsockname(void *name, int *namelen)
  312. {
  313.     struct sockaddr_atlk    addr;
  314.  
  315.     addr.family            =    AF_APPLETALK;
  316.     addr.addr            =    AppleTalkSockets.node;
  317.     addr.addr.aSocket    =    socket;
  318.  
  319.     memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(struct sockaddr_atlk))));
  320.  
  321.     return 0;
  322. }
  323.  
  324. int AppleTalkSocket::getpeername(void *name, int *namelen)
  325. {
  326.     struct sockaddr_atlk    addr;
  327.  
  328.     if (!peer.aNet && !peer.aNode && !peer.aSocket)
  329.         return GUSI_error(ENOTCONN);
  330.  
  331.     addr.family            =    AF_APPLETALK;
  332.     addr.addr            =    peer;
  333.  
  334.     memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(struct sockaddr_atlk))));
  335.  
  336.     return 0;
  337. }
  338.  
  339. /********************* ADSPSocket members *********************/
  340.  
  341. void ADSPCompletion(AnnotatedADSPParamBlock * pb)
  342. {
  343.     pb->sock->Ready();
  344. }
  345.  
  346. #if !GENERATINGCFM
  347. #ifdef __MWERKS__
  348. AnnotatedADSPParamBlock * GetADSPInfo() : __D0 = 0x2008;            // MOVE.L A0,D0
  349. #else
  350. AnnotatedADSPParamBlock * GetADSPInfo() = 0x2008;                    // MOVE.L A0,D0
  351. #endif
  352.  
  353. pascal void ADSPCompletion68K()
  354. {
  355.     AnnotatedADSPParamBlock *    pb        =    GetADSPInfo();
  356.     long saveA5                             =  SetA5(long(pb->sock->processA5));
  357.     
  358.     ADSPCompletion(pb);
  359.     
  360.     SetA5(saveA5);
  361. }
  362.  
  363. #define uADSPCompletion    ADSPCompletion68K
  364.  
  365. #else
  366. RoutineDescriptor    uADSPCompletion =
  367.         BUILD_ROUTINE_DESCRIPTOR(uppADSPCompletionProcInfo, ADSPCompletion);    
  368. #endif
  369.  
  370. ADSPSocket::ADSPSocket(u_char sock)
  371.     :    AppleTalkSocket(sock)
  372. {
  373.     ccb            =    nil;
  374.     pb                =    nil;
  375.     bufs             =    nil;
  376.  
  377.     if (!AppleTalkSockets.GetDSP())
  378.         GUSI_error(EPFNOSUPPORT);                    // Just an educated guess
  379. }
  380.  
  381. ADSPSocket::~ADSPSocket()
  382. {
  383.     UnInit(false);
  384. }
  385.  
  386. inline Boolean ADSPSocket::Waiting()
  387. {
  388.     return pb->ioResult == 1 && !(ccb->userFlags & (eClosed | eTearDown));
  389. }
  390.  
  391. inline Boolean ADSPSocket::Up()
  392. {
  393.     return !(ccb->userFlags & (eClosed | eTearDown));
  394. }
  395.  
  396. int ADSPSocket::listen(int)
  397. {
  398.     if (ccb)
  399.         return GUSI_error(EISCONN);
  400.  
  401.     ccb     =    new TRCCB;
  402.     if (!ccb)
  403.         goto memErrCCB;
  404.  
  405.     pb        =    new AnnotatedADSPParamBlock(this);
  406.     if (!pb)
  407.         goto memErrPB;
  408.  
  409.     pb->ioCRefNum                        =    AppleTalkSockets.GetDSP();
  410.     pb->csCode                            =    dspCLInit;
  411.     pb->u.initParams.ccbPtr            =    ccb;
  412.     pb->u.initParams.localSocket    =    socket;
  413.  
  414.     if (PBControlSync(ParmBlkPtr(pb)))
  415.         goto memErr;
  416.  
  417.     socket        =    pb->u.initParams.localSocket;
  418.  
  419.     if (symaddr)
  420.         symaddr->Register(socket);
  421.  
  422.     pb->csCode                                =    dspCLListen;
  423.     pb->ioCompletion                        =    ADSPCompletionUPP(&uADSPCompletion);
  424.     pb->u.openParams.filterAddress    =    NoFilter;
  425.  
  426.     PBControlAsync(ParmBlkPtr(pb));
  427.  
  428.     return 0;
  429.  
  430. memErr:
  431.     delete pb;
  432.     pb    =    nil;
  433. memErrPB:
  434.     delete ccb;
  435.     ccb    =    nil;
  436. memErrCCB:
  437.     return GUSI_error(ENOMEM);
  438. }
  439.  
  440. int ADSPSocket::Init()
  441. {
  442.     if (ccb)
  443.         if (pb->csCode == dspOpen && pb->ioResult && pb->ioResult != 1)
  444.             return 0;                            // Second chance for lose on open
  445.         else
  446.             return GUSI_error(EISCONN);    // Got a live un', don't reconnect
  447.  
  448.     ccb     =    new TRCCB;
  449.     if (!ccb)
  450.         goto memErrCCB;
  451.  
  452.     pb        =    new AnnotatedADSPParamBlock(this);
  453.     if (!pb)
  454.         goto memErrPB;
  455.  
  456.     bufs    =    new ADSPSockBuffers;
  457.     if (!bufs)
  458.         goto memErrBufs;
  459.  
  460.     pb->ioCRefNum                        =    AppleTalkSockets.GetDSP();
  461.     pb->csCode                            =    dspInit;
  462.     pb->u.initParams.ccbPtr            =    ccb;
  463.     pb->u.initParams.userRoutine    =    nil;
  464.     pb->u.initParams.sendQSize        =    bufs->qSize;
  465.     pb->u.initParams.sendQueue        =    bufs->sendBuf;
  466.     pb->u.initParams.recvQSize        =    bufs->qSize;
  467.     pb->u.initParams.recvQueue        =    bufs->recvBuf;
  468.     pb->u.initParams.attnPtr        =    bufs->attnBuf;
  469.     pb->u.initParams.localSocket    =    socket;
  470.  
  471.     if (!PBControlSync(ParmBlkPtr(pb)))    {
  472.         socket        =    pb->u.initParams.localSocket;
  473.  
  474.         if (symaddr)
  475.             symaddr->Register(socket);
  476.  
  477.         return 0;
  478.     }
  479.  
  480.     delete bufs;
  481.     bufs    =    nil;
  482. memErrBufs:
  483.     delete pb;
  484.     pb        =    nil;
  485. memErrPB:
  486.     delete ccb;
  487.     ccb    =    nil;
  488. memErrCCB:
  489.     return GUSI_error(ENOMEM);
  490. }
  491.  
  492. void ADSPSocket::UnInit(Boolean abort)
  493. {
  494.     if (ccb && pb)    {
  495.         pb->csCode                    =    bufs ? dspRemove : dspCLRemove;
  496.         pb->u.closeParams.abort    =    abort;
  497.  
  498.         PBControlSync(ParmBlkPtr(pb));
  499.     }
  500.  
  501.     if (ccb)
  502.         delete ccb;
  503.     if (pb)
  504.         delete pb;
  505.     if (bufs)
  506.         delete bufs;
  507.     
  508.     ccb    =    nil;
  509.     pb        =    nil;
  510.     bufs    =    nil;
  511. }
  512.  
  513. int ADSPSocket::connect(void *sa_name, int)
  514. {
  515.     switch (*(short *) sa_name)    {
  516.     case AF_APPLETALK:
  517.         {
  518.             sockaddr_atlk *    addr     =    (struct sockaddr_atlk *) sa_name;
  519.             peer                            =    addr->addr;
  520.         }
  521.         break;
  522.     case ATALK_SYMADDR:
  523.         {
  524.             struct sockaddr_atlk_sym *    addr     =     (struct sockaddr_atlk_sym *) sa_name;
  525.  
  526.             if (AtlkLookup(addr->name, &peer))
  527.                 return -1;
  528.         }
  529.         break;
  530.     default:
  531.         return GUSI_error(EAFNOSUPPORT);
  532.     }
  533.  
  534.     if (Init())
  535.         return -1;
  536.  
  537.     pb->csCode                                =    dspOpen;
  538.     pb->ioCompletion                        =    ADSPCompletionUPP(&uADSPCompletion);
  539.     pb->u.openParams.remoteAddress    =    peer;
  540.     pb->u.openParams.filterAddress    =    NoFilter;
  541.     pb->u.openParams.ocMode                =    ocRequest;
  542.     pb->u.openParams.ocInterval        =    0;
  543.     pb->u.openParams.ocMaximum            =    0;
  544.  
  545.     PBControlAsync(ParmBlkPtr(pb));
  546.  
  547.     if (nonblocking)
  548.         return GUSI_error(EINPROGRESS);
  549.  
  550.     SAFESPIN(Waiting(), SP_MISC, 0);
  551.  
  552.     if (errno)    {
  553.         UnInit(true);
  554.         
  555.         return -1;
  556.     } else if (pb->ioResult == noErr) {
  557.         return 0;
  558.     } else
  559.         return GUSI_error(ECONNREFUSED);
  560. }
  561.  
  562. Socket * ADSPSocket::accept(void * address, int * addrlen)
  563. {
  564.     ADSPSocket *    newsock;
  565.     sockaddr_atlk    addr;
  566.  
  567.     if (!pb || pb->csCode != dspCLListen)
  568.         return (Socket *) GUSI_error_nil(ENOTCONN);
  569.  
  570.     if (nonblocking && pb->ioResult == 1)
  571.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  572.  
  573.     SPINP(Waiting(), SP_MISC, 0);
  574.  
  575.     if (pb->ioResult)
  576.         return (Socket *) GUSI_error_nil(EINVAL);
  577.  
  578.     newsock    =    new ADSPSocket(socket);
  579.  
  580.     if (!newsock)
  581.         return (Socket *) GUSI_error_nil(ENOMEM);
  582.     if (newsock->Init())
  583.         return (Socket *) nil;
  584.  
  585.     newsock->pb->csCode                            =    dspOpen;
  586.     newsock->pb->ioCompletion                    =    ADSPCompletionUPP(&uADSPCompletion);
  587.     newsock->pb->u.openParams                    =    pb->u.openParams;
  588.     newsock->pb->u.openParams.ocMode            =    ocAccept;
  589.     newsock->pb->u.openParams.ocInterval    =    0;
  590.     newsock->pb->u.openParams.ocMaximum        =    0;
  591.     PBControlAsync(ParmBlkPtr(newsock->pb));
  592.  
  593.     SAFESPIN(newsock->Waiting(), SP_MISC, 0);
  594.  
  595.     pb->csCode                                =    dspCLListen;
  596.     pb->ioCompletion                        =    ADSPCompletionUPP(&uADSPCompletion);
  597.     pb->u.openParams.filterAddress    =    NoFilter;
  598.  
  599.     PBControlAsync(ParmBlkPtr(pb));
  600.  
  601.     if (errno || newsock->pb->ioResult)    {
  602.         delete newsock;
  603.  
  604.         return (Socket *) (errno ? nil : GUSI_error_nil(ECONNREFUSED));
  605.     }
  606.  
  607.     if (address && addrlen)    {
  608.         addr.family    =    AF_APPLETALK;
  609.         addr.addr    =    pb->u.openParams.remoteAddress;
  610.  
  611.         memcpy(address, &addr, *addrlen = min(*addrlen, int(sizeof(sockaddr_atlk))));
  612.     }
  613.  
  614.     return newsock;
  615. }
  616.  
  617. int ADSPSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  618. {
  619.     // To avoid blocking in the ADSP driver, if no data is available, we only read
  620.     // 1 byte and then the rest of the segment that has arrived
  621.     
  622.     int    trylen;
  623.     int     actlen;
  624.     
  625.     if (from)
  626.         getpeername(from, fromlen);
  627.     if (flags & ~MSG_OOB)
  628.         return GUSI_error(EOPNOTSUPP);
  629.     if (!pb)
  630.         return GUSI_error(ENOTCONN);
  631.  
  632.     if (pb->csCode == dspOpen && pb->ioResult)    {
  633.         if (pb->ioResult == 1)    {
  634.             if (nonblocking)
  635.                 return GUSI_error(EWOULDBLOCK);
  636.  
  637.             SPIN(Waiting(), SP_MISC, 0);
  638.         }
  639.  
  640.         if (pb->ioResult)
  641.             return GUSI_error(ECONNREFUSED);
  642.     }
  643.  
  644.     if (flags & MSG_OOB)
  645.         if (ccb->userFlags & eAttention)    {
  646.             memcpy(Ptr(buffer), ccb->attnPtr, buflen = min(buflen, ccb->attnSize));
  647.  
  648.             ccb->userFlags ^= eAttention;
  649.  
  650.             return buflen;
  651.         } else
  652.             return GUSI_error(EINVAL);
  653.  
  654.     pb->csCode            =    dspStatus;
  655.  
  656.     PBControlSync(ParmBlkPtr(pb));
  657.  
  658.     if (pb->u.statusParams.recvQPending)
  659.         trylen = pb->u.statusParams.recvQPending;
  660.     else
  661.         if (nonblocking)
  662.             return GUSI_error(EWOULDBLOCK);
  663.         else if (readShutDown)
  664.             return 0;
  665.         else
  666.             trylen = 1;
  667.  
  668.     while (!pb->u.statusParams.recvQPending && Up()) {
  669.         SPIN(0, SP_STREAM_READ, 0);
  670.         PBControlSync(ParmBlkPtr(pb));
  671.     }
  672.  
  673.     pb->csCode                    =    dspRead;
  674.     pb->ioCompletion            =    ADSPCompletionUPP(&uADSPCompletion);
  675.     pb->u.ioParams.reqCount    =    min(buflen, trylen);
  676.     pb->u.ioParams.dataPtr    =    (u_char *) buffer;
  677.  
  678.     PBControlAsync(ParmBlkPtr(pb));
  679.     
  680.     SPIN(Waiting(), SP_STREAM_READ, 0);
  681.     
  682.     actlen = pb->u.ioParams.actCount;
  683.  
  684.     if (pb->ioResult)
  685.         readShutDown = true;
  686.     else {
  687.         buflen -= actlen;
  688.         
  689.         if (actlen == 1 && buflen) {
  690.             pb->csCode            =    dspStatus;
  691.  
  692.             PBControlSync(ParmBlkPtr(pb));
  693.             
  694.             if (trylen = pb->u.statusParams.recvQPending) {
  695.                 pb->csCode                    =    dspRead;
  696.                 pb->u.ioParams.reqCount    =    min(buflen, trylen);
  697.                 pb->u.ioParams.dataPtr    =    ((u_char *) buffer) + actlen;
  698.                 
  699.                 if (PBControlSync(ParmBlkPtr(pb)))
  700.                     readShutDown = true;
  701.                 
  702.                 actlen += pb->u.ioParams.actCount;
  703.             }
  704.         }
  705.     }
  706.  
  707.     return actlen;
  708. }
  709.  
  710. int ADSPSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  711. {
  712.     if (to)
  713.         return GUSI_error(EOPNOTSUPP);
  714.     if (flags & ~MSG_OOB)
  715.         return GUSI_error(EOPNOTSUPP);
  716.     if (!pb)
  717.         return GUSI_error(ENOTCONN);
  718.  
  719.     if (pb->csCode == dspOpen && (pb->ioResult || !Up()))    {
  720.         if (Waiting())    {
  721.             if (nonblocking)
  722.                 return GUSI_error(EWOULDBLOCK);
  723.  
  724.             SPIN(Waiting(), SP_MISC, 0);
  725.         }
  726.  
  727.         if (pb->ioResult)
  728.             return GUSI_error(ECONNREFUSED);
  729.     }
  730.  
  731.     if (writeShutDown)
  732.             return GUSI_error(ESHUTDOWN);
  733.  
  734.     if (flags & MSG_OOB)    {
  735.         if (buflen < 0 || buflen > 570)
  736.             return GUSI_error(EINVAL);
  737.  
  738.         pb->csCode                        =    dspAttention;
  739.         pb->u.attnParams.attnCode    =    0;
  740.         pb->u.attnParams.attnSize    =    buflen;
  741.         pb->u.attnParams.attnData    =    (unsigned char *) buffer;
  742.  
  743.         PBControlSync(ParmBlkPtr(pb));
  744.  
  745.         if (pb->ioResult)
  746.             return GUSI_error(EINVAL);
  747.         else
  748.             return buflen;
  749.     }
  750.  
  751.     if (nonblocking)    {
  752.         pb->csCode    =    dspStatus;
  753.  
  754.         PBControlSync(ParmBlkPtr(pb));
  755.  
  756.         if (!pb->u.statusParams.sendQFree)
  757.             return GUSI_error(EWOULDBLOCK);
  758.     }
  759.  
  760.     pb->csCode                    =    dspWrite;
  761.     pb->ioCompletion            =    ADSPCompletionUPP(&uADSPCompletion);
  762.     pb->u.ioParams.reqCount    =
  763.         nonblocking
  764.             ?     min(buflen, pb->u.statusParams.sendQFree)
  765.             :    buflen;
  766.     pb->u.ioParams.dataPtr    =    (u_char *) buffer;
  767.     pb->u.ioParams.eom        =    false;
  768.     pb->u.ioParams.flush        =    true;
  769.  
  770.     PBControlAsync(ParmBlkPtr(pb));
  771.  
  772.     SPIN(Waiting(), SP_STREAM_WRITE, 0);
  773.  
  774.     if (pb->ioResult)
  775.         writeShutDown = true;
  776.  
  777.     return pb->u.ioParams.actCount;
  778. }
  779.  
  780. int ADSPSocket::shutdown(int how)
  781. {
  782.     if (how < 0 || how > 2)
  783.         return GUSI_error(EINVAL);
  784.  
  785.     if (how)
  786.         writeShutDown    =    true;
  787.     if (!(how & 1))
  788.         readShutDown    =    true;
  789.  
  790.     return 0;
  791. }
  792.  
  793. int ADSPSocket::ioctl(unsigned int request, void *argp)
  794. {
  795.     switch (request)    {
  796.     case FIONREAD:
  797.         if (!pb)
  798.             return GUSI_error(ENOTCONN);
  799.  
  800.         pb->csCode            =    dspStatus;
  801.  
  802.         PBControlSync(ParmBlkPtr(pb));
  803.  
  804.         *(unsigned long *) argp    = pb->u.statusParams.recvQPending;
  805.  
  806.         return 0;
  807.     default:
  808.         return AppleTalkSocket::ioctl(request, argp);
  809.     }
  810. }
  811.  
  812. int ADSPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  813. {
  814.     int    goodies = 0;
  815.  
  816.     if (pb) {
  817.         pb->csCode        =    dspStatus;
  818.         PBControlSync(ParmBlkPtr(pb));
  819.     }
  820.     
  821.     if (canRead)
  822.         if ( !pb || readShutDown || !Up() || pb->u.statusParams.recvQPending
  823.             ||    (pb->csCode == dspCLListen && pb->ioResult != 1)
  824.         )    {
  825.             *canRead = true;
  826.             ++goodies;
  827.         }
  828.  
  829.     if (canWrite)
  830.         if ( !pb || writeShutDown || !Up() || pb->u.statusParams.sendQFree != 0
  831.             || (pb->csCode == dspOpen && pb->ioResult != 1)
  832.         )    {
  833.             *canWrite = true;
  834.             ++goodies;
  835.         }
  836.         
  837.     if (exception && (ccb->userFlags & eAttention)) {
  838.         *exception = true;
  839.         ++goodies;
  840.     }
  841.  
  842.     return goodies;
  843. }
  844.  
  845. /********************* AppleTalkSocketDomain members **********************/
  846.  
  847. extern "C" void GUSIwithAppleTalkSockets()
  848. {
  849.     AppleTalkSockets.DontStrip();
  850. }
  851.  
  852. AppleTalkSocketDomain::AppleTalkSocketDomain()
  853.     :    SocketDomain(AF_APPLETALK)
  854. {
  855.     dspRefNum    =    0;
  856.     node.aNet    =    0xFFFF;
  857.     node.aNode    =    0;
  858.     node.aSocket=    0;
  859. }
  860.  
  861. void AppleTalkSocketDomain::DoMPPOpen()
  862. {
  863.     short    myNode;
  864.     short    myNet;
  865.  
  866.     if (AppleTalkIdentity(myNet, myNode))    {
  867.         node.aNet    =    0xFFFF;
  868.         node.aNode    =    0;
  869.         node.aSocket=    0;
  870.     } else {
  871.         node.aNet    =    myNet;
  872.         node.aNode    =    (u_char) myNode;
  873.         node.aSocket=    1;
  874.     }
  875. }
  876.  
  877. Boolean AppleTalkSocketDomain::Validate()
  878. {
  879.     if (!node.aSocket)
  880.         DoMPPOpen();
  881.  
  882.     return node.aSocket != 0;
  883. }
  884.  
  885. short    AppleTalkSocketDomain::GetDSP()
  886. {
  887.     if (!dspRefNum)
  888.         if (OpenDriver((StringPtr) "\p.DSP", &dspRefNum))
  889.             dspRefNum    =    0;
  890.  
  891.     return dspRefNum;
  892. }
  893.  
  894. Socket * AppleTalkSocketDomain::socket(int type, short)
  895. {
  896.     AppleTalkSocket * sock    =    nil;
  897.  
  898.     errno    =    0;
  899.  
  900.     if (!Validate())
  901.         GUSI_error(ENETDOWN);
  902.     else
  903.         switch (type)    {
  904.         case SOCK_STREAM:
  905.             sock = new ADSPSocket();
  906.             break;
  907.         default:
  908.             GUSI_error(ESOCKTNOSUPPORT);
  909.         }
  910.  
  911.     if (sock && errno)    {
  912.         delete sock;
  913.  
  914.         return nil;
  915.     } else
  916.         return sock;
  917. }
  918.  
  919. int AppleTalkSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  920. {
  921.     sa_constr_atlk *     constr = (sa_constr_atlk *) constraint;
  922.     Point                    where;
  923.     NBPReply                reply;
  924.     sockaddr_atlk        addr;
  925.     Str255                promp;
  926.     NLType                dummy;
  927.  
  928.     if (!hasStdNBP)
  929.         return GUSI_error(EOPNOTSUPP);
  930.  
  931.     if (!Validate())
  932.         return GUSI_error(ENETDOWN);
  933.  
  934.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  935.         return GUSI_error(EINVAL);
  936.         
  937.     SetPt(&where, 100, 100);
  938.  
  939.     memset(&reply.theEntity, 0, sizeof(EntityName));
  940.     memcpy(&reply.theEntity.zoneStr, (StringPtr) "\p*", 2);
  941.  
  942.     CopyC2PStr(prompt, promp);
  943.  
  944.     if (
  945.         StandardNBP(
  946.             where,
  947.             promp,
  948.             constr ? constr->numTypes : -1,
  949.             constr ? constr->types : dummy,
  950.             NameFilterUPP(nil),
  951.             ZoneFilterUPP(nil),
  952.             DlgHookUPP(nil),
  953.             &reply)
  954.         != nlOk
  955.     )
  956.         return GUSI_error(EINTR);
  957.  
  958.     addr.family    =    AF_APPLETALK;
  959.     addr.addr    =     reply.theAddr;
  960.  
  961.     memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(sockaddr_atlk))));
  962.  
  963.     return 0;
  964. }
  965.  
  966. /*********************** AtlkSymAddr members ************************/
  967.  
  968. static int EntityLen(const EntityName & name)
  969. {
  970.     Ptr    nm    =    Ptr(&name);
  971.     int    l1    =    *nm+1;
  972.     nm += l1;
  973.     int    l2    =    *nm+1;
  974.     nm += l2;
  975.     int    l3    =    *nm+1;
  976.  
  977.     return l1+l2+l3;
  978. }
  979.  
  980. AtlkSymAddr::AtlkSymAddr(const EntityName & name)
  981. {
  982.     int                len    =    EntityLen(name);
  983.  
  984.     errno = 0;
  985.  
  986.     if (!AppleTalkSockets.Validate())    {
  987.         GUSI_error(ENETDOWN);
  988.  
  989.         return;
  990.     }
  991.  
  992.     nte    =    (NamesTableEntry *) NewPtr(9+len);
  993.     legit    =    false;
  994.  
  995.     if (!nte)    {
  996.         GUSI_error(ENOMEM);
  997.  
  998.         return;
  999.     }
  1000.  
  1001.     nte->qNext =    nil;
  1002.     memcpy(&nte->nt.entityData, &name, len);
  1003. }
  1004.  
  1005. void AtlkSymAddr::Register(u_char socket)
  1006. {
  1007.     MPPParamBlock    mpp;
  1008.  
  1009.     errno = 0;
  1010.  
  1011.     nte->nt.nteAddress.aSocket    =    socket;
  1012.  
  1013.     mpp.NBPinterval    =    8;
  1014.     mpp.NBPcount        =    3;
  1015.     mpp.NBPntQElPtr    =    Ptr(nte);
  1016.     mpp.NBPverifyFlag    =    true;
  1017.     PRegisterName(&mpp, false);
  1018.  
  1019.     if (mpp.MPPioResult)    {
  1020.         DisposPtr(Ptr(nte));
  1021.  
  1022.         GUSI_error((mpp.MPPioResult == nbpDuplicate) ? EADDRINUSE : EINVAL);
  1023.     } else
  1024.         legit    =    true;
  1025. }
  1026.  
  1027. AtlkSymAddr::~AtlkSymAddr()
  1028. {
  1029.     if (nte)    {
  1030.         if (legit) {
  1031.             MPPParamBlock    mpp;
  1032.  
  1033.             mpp.NBPentityPtr    =    Ptr(&nte->nt.entityData);
  1034.             PRemoveName(&mpp, false);
  1035.         }
  1036.  
  1037.         DisposPtr(Ptr(nte));
  1038.     }
  1039. }
  1040.  
  1041. int AtlkLookup(const EntityName & name, AddrBlock * addr)
  1042. {
  1043.     EntityName        ent;
  1044.     char                found[256];
  1045.     MPPParamBlock    mpp;
  1046.  
  1047.     mpp.NBPinterval        =    8;
  1048.     mpp.NBPcount            =    3;
  1049.     mpp.NBPentityPtr        =    Ptr(&name);
  1050.     mpp.NBPretBuffPtr        =    found;
  1051.     mpp.NBPretBuffSize    =    256;
  1052.     mpp.NBPmaxToGet        =    1;
  1053.     PLookupName(&mpp, false);
  1054.     if (!mpp.MPPioResult)
  1055.         NBPExtract(found, mpp.NBPnumGotten, 1, &ent, addr);
  1056.  
  1057.     if (mpp.MPPioResult)
  1058.         return GUSI_error(ECONNREFUSED);
  1059.  
  1060.     return 0;
  1061. }
  1062.